<template>
  <div>
    <TresGroup>
      <Base :blocks="mapChildren" :baseHeight="baseHeight" />
      <Mid
        :blocks="mapChildren"
        :baseHeight="baseHeight"
        :midHeightScale="midHeightScale"
      />
      <Top
        :blocks="mapChildren"
        :baseHeight="baseHeight"
        :midHeightScale="midHeightScale"
        :topHeightScale="topHeightScale"
        :values="values"
        :mapCenter="mapCenter"
      />
    </TresGroup>
    21
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import * as THREE from "three";
import * as d3 from "d3-geo";
import Base from "./base.vue";
import Mid from "./mid.vue";
import Top from "./top.vue";

const props = defineProps({
  baseHeight: {
    type: Number,
    required: true,
  },
  midHeightScale: {
    type: Number,
    required: true,
  },
  topHeightScale: {
    type: Number,
    required: true,
  },
  values: {
    type: Object,
    required: true,
  },
  geoJson: {
    type: Object,
    required: true,
  },
  mapCenter: {
    type: Array,
    required: true,
  },
});

const map = ref(new THREE.Object3D());
const mapChildren = ref([]);

// 数据处理函数 - 将不规范的数据规范化
const processing = (oriData, values) => {
  oriData.features.forEach((region) => {
    region.properties.value = values.features[region.properties.name];
    if (typeof region.geometry.coordinates[0][0][0] === "number") {
      const temp = region.geometry.coordinates[0];
      region.geometry.coordinates[0] = [temp];
    }
  });
  return oriData;
};

onMounted(() => {
  const projection = d3.geoMercator().center(props.mapCenter).translate([0, 0]);

  processing(props.geoJson, props.values).features.forEach((element) => {
    const region = new THREE.Object3D();
    const coordinates = element.geometry.coordinates;

    coordinates.forEach((multiPolygon) => {
      multiPolygon.forEach((polygon) => {
        const shape = new THREE.Shape();
        const lineMaterial = new THREE.LineBasicMaterial({
          color: "#ffffff",
        });
        const lineGeometry = new THREE.BufferGeometry();

        const vertices = [];
        for (let i = 0; i < polygon.length; i++) {
          let x = null;
          let y = null;
          if (polygon[i] instanceof Array) {
            [x, y] = projection(polygon[i]);
            if (i === 0) {
              shape.moveTo(x, -y);
            }
            shape.lineTo(x, -y);
            vertices.push(
              x,
              -y,
              props.baseHeight * props.topHeightScale + 0.001
            );
          }
        }
        lineGeometry.setAttribute(
          "position",
          new THREE.BufferAttribute(new Float32Array(vertices), 3)
        );

        const extrudeSettings = {
          depth: props.baseHeight,
          bevelEnabled: false,
        };

        const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
        const material = new THREE.MeshBasicMaterial();
        const mesh = new THREE.Mesh(geometry, material);
        const line = new THREE.Line(lineGeometry, lineMaterial);
        region.add(mesh);
        region.add(line);
      });
    });

    region.properties = element.properties;
    if (element.properties.centroid) {
      const [x, y] = projection(element.properties.centroid);
      region.properties._centroid = [x, y];
    }

    map.value.add(region);
  });

  mapChildren.value = map.value.children;
});
</script>
